home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / tcpcmd.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  18KB  |  798 lines

  1. /* TCP control and status routines
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * Mods by G1EMM
  5.  * Mods by WG7J
  6.  * Mods by WA3DSP
  7.  * Mods by PA0GRI
  8.  * Copyright 1992 Gerard J van der Grinten, PA0GRI
  9.  */
  10.  
  11. #include <stdio.h>
  12. #ifdef MSDOS
  13. #include <dos.h>
  14. #endif
  15. #include "global.h"
  16. #include "config.h"
  17. #include "timer.h"
  18. #include "mbuf.h"
  19. #include "netuser.h"
  20. #include "internet.h"
  21. #include "tcp.h"
  22. #include "cmdparse.h"
  23. #include "commands.h"
  24. #include "socket.h"
  25. #include "ctype.h"
  26.  
  27. #ifdef  TCPACCESS
  28. static int doaccess __ARGS((int argc,char *argv[],void *p));
  29. void addtaccess __ARGS((int32 target,unsigned int bits,int16 low,int16 high,int16 permit));
  30. #endif
  31. static int doirtt __ARGS((int argc,char *argv[],void *p));
  32. static int domss __ARGS((int argc,char *argv[],void *p));
  33. static int dortt __ARGS((int argc,char *argv[],void *p));
  34. static int dotcpkick __ARGS((int argc,char *argv[],void *p));
  35. static int dotcpreset __ARGS((int argc,char *argv[],void *p));
  36. static int dotcpretries __ARGS((int argc,char *argv[],void *p));
  37. static int dotcpstat __ARGS((int argc,char *argv[],void *p));
  38. static int dotcptimer __ARGS((int argc,char *argv[],void *p));
  39. static int dotcptr __ARGS((int argc,char *argv[],void *p));
  40. static int dowindow __ARGS((int argc,char *argv[],void *p));
  41. static int dosyndata __ARGS((int argc,char *argv[],void *p));
  42. static int doview __ARGS((int argc,char *argv[],void *p));
  43. static int dotcpblimit __ARGS((int argc,char *argv[],void *p));
  44. void rxtx_data_compute __ARGS((struct tcb *tcb,int32 *sent,int32 *recvd));
  45. #ifdef TCPACCESS
  46. struct rtaccess *TCPaccess = NULLACCESS; /* access list */
  47. #endif
  48.  
  49. /* TCP subcommand table */
  50. static struct cmds Tcpcmds[] = {
  51. #ifdef  TCPACCESS
  52.     "access",       doaccess,       0,      0, NULLCHAR,
  53. #endif
  54.     "blimit",       dotcpblimit,    0, 0,   NULLCHAR,
  55.     "irtt",         doirtt,         0, 0,   NULLCHAR,
  56.     "kick",         dotcpkick,      0, 2,   "tcp kick <tcb>",
  57.     "mss",          domss,          0, 0,   NULLCHAR,
  58.     "reset",        dotcpreset,     0, 2,   "tcp reset <tcb>",
  59.     "retries",      dotcpretries,   0,0,    NULLCHAR,
  60.     "rtt",          dortt,          0, 3,   "tcp rtt <tcb> <val>",
  61.     "status",       dotcpstat,      0, 0,   NULLCHAR,
  62.     "syndata",      dosyndata,      0, 0,   NULLCHAR,
  63.     "timertype",    dotcptimer,     0, 0,   NULLCHAR,
  64.     "trace",        dotcptr,        0, 0,   NULLCHAR,
  65.     "view",         doview,         0, 0,   NULLCHAR,
  66.     "window",       dowindow,       0, 0,   NULLCHAR,
  67.     NULLCHAR,
  68. };
  69. int
  70. dotcp(argc,argv,p)
  71. int argc;
  72. char *argv[];
  73. void *p;
  74. {
  75.     return subcmd(Tcpcmds,argc,argv,p);
  76. }
  77. static int
  78. dotcptr(argc,argv,p)
  79. int argc;
  80. char *argv[];
  81. void *p;
  82. {
  83.     return setbool(&Tcp_trace,"TCP state tracing",argc,argv);
  84. }
  85.  
  86. /* Eliminate a TCP connection */
  87. static int
  88. dotcpreset(argc,argv,p)
  89. int argc;
  90. char *argv[];
  91. void *p;
  92. {
  93.     register struct tcb *tcb;
  94.     
  95.     tcb = MK_FP(htoi(argv[1]),8);
  96.     if(!tcpval(tcb)){
  97.     tputs(Notval);
  98.         return 1;
  99.     }
  100.     reset_tcp(tcb);
  101.     return 0;
  102. }
  103.  
  104. /* Set initial round trip time for new connections */
  105. static int
  106. doirtt(argc,argv,p)
  107. int argc;
  108. char *argv[];
  109. void *p;
  110. {
  111.     struct tcp_rtt *tp;
  112.  
  113.     setlong(&Tcp_irtt,"TCP default irtt",argc,argv);
  114.     if(argc < 2){
  115.         for(tp = &Tcp_rtt[0];tp < &Tcp_rtt[RTTCACHE];tp++){
  116.             if(tp->addr != 0){
  117.                 if(tprintf("%s: srtt %lu mdev %lu\n",
  118.                  inet_ntoa(tp->addr),
  119.                  tp->srtt,tp->mdev) == EOF)
  120.                     break;
  121.             }
  122.         }
  123.     }
  124.     return 0;
  125. }
  126.  
  127. /* Set smoothed round trip time for specified TCB */
  128. static int
  129. dortt(argc,argv,p)
  130. int argc;
  131. char *argv[];
  132. void *p;
  133. {
  134.     register struct tcb *tcb;
  135.     tcb = MK_FP(htoi(argv[1]),8);
  136.     if(!tcpval(tcb)){
  137.         tprintf(Notval);
  138.         return 1;
  139.     }
  140.     tcb->srtt = atol(argv[2]);
  141.     return 0;
  142. }
  143.  
  144. /* Force a retransmission */
  145. static int
  146. dotcpkick(argc,argv,p)
  147. int argc;
  148. char *argv[];
  149. void *p;
  150. {
  151.     register struct tcb *tcb;
  152.     tcb = MK_FP(htoi(argv[1]),8);
  153.     if(kick_tcp(tcb) == -1){
  154.         tprintf(Notval);
  155.         return 1;
  156.     }
  157.     return 0;
  158. }
  159.  
  160. /* Set default maximum segment size */
  161. static int
  162. domss(argc,argv,p)
  163. int argc;
  164. char *argv[];
  165. void *p;
  166. {
  167.     return setshort(&Tcp_mss,"TCP MSS",argc,argv);
  168. }
  169.  
  170. /* Set default window size */
  171. static int
  172. dowindow(argc,argv,p)
  173. int argc;
  174. char *argv[];
  175. void *p;
  176. {
  177.     return setshort(&Tcp_window,"TCP window",argc,argv);    
  178. }
  179.  
  180. static int
  181. dosyndata(argc,argv,p)
  182. int argc;
  183. char *argv[];
  184. void *p;
  185. {
  186.     return setbool(&Tcp_syndata,"TCP syn+data piggybacking",argc,argv);
  187. }
  188.  
  189. extern int Tcp_retries;
  190.  
  191. /* Set maximum number of backoffs before resetting the connection */
  192. static int
  193. dotcpretries(argc,argv,p)
  194. int argc;
  195. char *argv[];
  196. void *p;
  197. {
  198.     return setint(&Tcp_retries,"max. retries",argc,argv);
  199. }
  200.  
  201. extern int Tcp_blimit;
  202.  
  203. /* Set backoff limit on the connection; from N1BEE */
  204. static int
  205. dotcpblimit(argc,argv,p)
  206. int argc;
  207. char *argv[];
  208. void *p;
  209. {
  210.     return setint(&Tcp_blimit,"backoff limit",argc,argv);
  211. }
  212.  
  213. #ifdef oldtcpstat
  214. static int tstat __ARGS((void));
  215.  
  216. /* Display status of TCBs */
  217. static int
  218. dotcpstat(argc,argv,p)
  219. int argc;
  220. char *argv[];
  221. void *p;
  222. {
  223.     register struct tcb *tcb;
  224.  
  225.     if(argc < 2){
  226.         tstat();
  227.     } else {
  228.  
  229.     tcb = MK_FP(htoi(argv[1]),8);
  230.     if(!tcpval(tcb))
  231.         tprintf(Notval);
  232.     else
  233.         st_tcp(tcb);
  234.     }
  235.     return 0;
  236. }
  237.  
  238. /* Dump TCP stats and summary of all TCBs
  239.  *     &TCB Rcv-Q Snd-Q  Local socket           Remote socket          State
  240.  *     1234     0     0  xxx.xxx.xxx.xxx:xxxxx  xxx.xxx.xxx.xxx:xxxxx  Established
  241.  */
  242. static int
  243. tstat()
  244. {
  245.     register int i;
  246.     register struct tcb *tcb;
  247.     int j;
  248.  
  249.     for(j=i=1;i<=NUMTCPMIB;i++){
  250.         if(Tcp_mib[i].name == NULLCHAR)
  251.             continue;
  252.         tprintf("(%2u)%-20s%10lu",i,Tcp_mib[i].name,
  253.          Tcp_mib[i].value.integer);
  254.         if(j++ % 2)
  255.             tprintf("     ");
  256.         else
  257.             tprintf("\n");
  258.     }
  259.     if((j % 2) == 0)
  260.         tprintf("\n");
  261.  
  262. #ifdef UNIX
  263.     tprintf("&TCB     Rcv-Q Snd-Q  Local socket           Remote socket          State\n");
  264. #else
  265.     tprintf("&TCB Rcv-Q Snd-Q  Local socket           Remote socket          State\n");
  266. #endif
  267.     for(tcb=Tcbs;tcb != NULLTCB;tcb = tcb->next){
  268. #ifdef UNIX
  269.         tprintf("%8.8x%6u%6u  ",FP_SEG(tcb),tcb->rcvcnt,tcb->sndcnt);
  270. #else
  271.     tprintf("%4.4x%6u%6u  ",FP_SEG(tcb),tcb->rcvcnt,tcb->sndcnt);
  272. #endif
  273.         tprintf("%-23s",pinet(&tcb->conn.local));
  274.         tprintf("%-23s",pinet(&tcb->conn.remote));
  275.         tprintf("%-s",Tcpstates[tcb->state]);
  276.         if(tcb->state == TCP_LISTEN && tcb->flags.clone)
  277.             tprintf(" (S)");
  278.         if(tprintf("\n") == EOF)
  279.             return 0;
  280.     }
  281.     return 0;
  282. }
  283.  
  284. #else
  285. /* New tcp stat by Doug Crompton, wa3dsp */
  286. static int tstat __ARGS((int flag));
  287.  
  288. /* Display status of TCBs */
  289. static int
  290. dotcpstat(argc,argv,p)
  291. int argc;
  292. char *argv[];
  293. void *p;
  294. {
  295.     struct tcb *tcb;
  296.  
  297.     if(argc < 2){
  298.     tstat(0);
  299.     } else {
  300.     if (toupper(argv[1][0])=='A') {
  301.         tstat(1);
  302.     } else {
  303.         tcb = MK_FP(htoi(argv[1]),8);
  304.         if(!tcpval(tcb))
  305.         tputs(Notval);
  306.         else
  307.         st_tcp(tcb);
  308.     }
  309.     }
  310.     return 0;
  311. }
  312.  
  313. /* Dump TCP stats and summary of all TCBs
  314.  *     &TCB Rcv-Q Snd-Q  Local socket           Remote socket          State
  315.  *     1234     0     0  xxx.xxx.xxx.xxx:xxxxx  xxx.xxx.xxx.xxx:xxxxx  Established
  316.  */
  317. static int
  318. tstat(int flag)
  319. {
  320.     int i;
  321.     struct tcb *tcb;
  322.     int j;
  323.  
  324.     for(j=i=1;i<=NUMTCPMIB;i++){
  325.     if(Tcp_mib[i].name == NULLCHAR)
  326.         continue;
  327.     tprintf("(%2u)%-20s%10lu",i,Tcp_mib[i].name,
  328.          Tcp_mib[i].value.integer);
  329.     if(j++ % 2)
  330.         tputs("     ");
  331.     else
  332.         tputs("\n");
  333.     }
  334.     if((j % 2) == 0)
  335.     tputs("\n");
  336.  
  337. #ifdef UNIX
  338.     tprintf("&TCB     Rcv-Q Snd-Q  Local socket           Remote socket          State\n");
  339. #else
  340.     tprintf("&TCB Rcv-Q Snd-Q  Local socket           Remote socket          State\n");
  341. #endif
  342.     for(tcb=Tcbs;tcb != NULLTCB;tcb = tcb->next){
  343.     if(tcb->state == TCP_LISTEN && !flag)
  344.         continue;
  345. #ifdef UNIX
  346.         tprintf("%8.8lx%6u%6u  ",FP_SEG(tcb),tcb->rcvcnt,tcb->sndcnt);
  347. #else
  348.     tprintf("%4.4x%6u%6u  ",FP_SEG(tcb),tcb->rcvcnt,tcb->sndcnt);
  349. #endif
  350.     tprintf("%-23s",pinet(&tcb->conn.local));
  351.     tprintf("%-23s",pinet(&tcb->conn.remote));
  352.     tprintf("%-s",Tcpstates[tcb->state]);
  353.     if(tcb->state == TCP_LISTEN && tcb->flags.clone)
  354.         tputs(" (S)");
  355.     if(tputs("\n") == EOF)
  356.         return 0;
  357.     }
  358.     return 0;
  359. }
  360.  
  361. #endif
  362.  
  363. /* Dump a TCP control block in detail */
  364. void
  365. st_tcp(tcb)
  366. struct tcb *tcb;
  367. {
  368.     int32 sent,recvd;
  369.  
  370.     if(tcb == NULLTCB)
  371.         return;
  372.  
  373.     rxtx_data_compute(tcb,&sent,&recvd);
  374.  
  375.     tprintf("Local: %s",pinet(&tcb->conn.local));
  376.     tprintf(" Remote: %s",pinet(&tcb->conn.remote));
  377.     tprintf(" State: %s\n",Tcpstates[tcb->state]);
  378.     tprintf("      Init seq    Unack     Next Resent CWind Thrsh  Wind  MSS Queue      Total\n");
  379.     tprintf("Send:");
  380.     tprintf("%9lx",tcb->iss);
  381.     tprintf("%9lx",tcb->snd.una);
  382.     tprintf("%9lx",tcb->snd.nxt);
  383.     tprintf("%7lu",tcb->resent);
  384.     tprintf("%6u",tcb->cwind);
  385.     tprintf("%6u",tcb->ssthresh);
  386.     tprintf("%6u",tcb->snd.wnd);
  387.     tprintf("%5u",tcb->mss);
  388.     tprintf("%6u",tcb->sndcnt);
  389.     tprintf("%11lu\n",sent);
  390.  
  391.     tprintf("Recv:");
  392.     tprintf("%9lx",tcb->irs);
  393.     tprintf("         ");
  394.     tprintf("%9lx",tcb->rcv.nxt);
  395.     tprintf("%7lu",tcb->rerecv);
  396.     tprintf("      ");
  397.     tprintf("      ");
  398.     tprintf("%6u",tcb->rcv.wnd);
  399.     tprintf("     ");
  400.     tprintf("%6u",tcb->rcvcnt);
  401.     tprintf("%11lu\n",recvd);
  402.  
  403.     if(tcb->reseq != (struct reseq *)NULL){
  404.         register struct reseq *rp;
  405.  
  406.         tprintf("Reassembly queue:\n");
  407.         for(rp = tcb->reseq;rp != (struct reseq *)NULL; rp = rp->next){
  408.             if(tprintf("  seq x%lx %u bytes\n",
  409.              rp->seg.seq,rp->length) == EOF)
  410.                 return;
  411.         }
  412.     }
  413.     if(tcb->backoff > 0)
  414.         tprintf("Backoff %u ",tcb->backoff);
  415.     if(tcb->flags.retran)
  416.         tprintf("Retrying ");
  417.     switch(tcb->timer.state){
  418.     case TIMER_STOP:
  419.         tprintf("Timer stopped ");
  420.         break;
  421.     case TIMER_RUN:
  422.         tprintf("Timer running (%ld/%ld ms) ",
  423.          (long)read_timer(&tcb->timer),
  424.          (long)dur_timer(&tcb->timer));
  425.         break;
  426.     case TIMER_EXPIRE:
  427.         tprintf("Timer expired ");
  428.     }
  429.     tprintf("SRTT %ld ms Mean dev %ld ms\n",tcb->srtt,tcb->mdev);
  430. }
  431.  
  432. void
  433. rxtx_data_compute(tcb,sent,recvd)
  434. struct tcb *tcb;
  435. int32 *sent;
  436. int32 *recvd;
  437. {
  438.  
  439.     /* Compute total data sent and received; take out SYN and FIN */
  440.     *sent = tcb->snd.una - tcb->iss;        /* Acknowledged data only */
  441.     *recvd = tcb->rcv.nxt - tcb->irs;
  442.     switch(tcb->state){
  443.     case TCP_LISTEN:
  444.     case TCP_SYN_SENT:      /* Nothing received or acked yet */
  445.         *sent = *recvd = 0;     
  446.         break;
  447.     case TCP_SYN_RECEIVED:
  448.         (*recvd)--;     /* Got SYN, no data acked yet */
  449.         *sent = 0;
  450.         break;
  451.     case TCP_ESTABLISHED:   /* Got and sent SYN */
  452.     case TCP_FINWAIT1:      /* FIN not acked yet */
  453.         (*sent)--;
  454.         (*recvd)--;
  455.         break;
  456.     case TCP_FINWAIT2:      /* Our SYN and FIN both acked */
  457.         *sent -= 2;
  458.         (*recvd)--;
  459.         break;
  460.     case TCP_CLOSE_WAIT:    /* Got SYN and FIN, our FIN not yet acked */
  461.     case TCP_CLOSING:
  462.     case TCP_LAST_ACK:
  463.         (*sent)--;
  464.         *recvd -= 2;
  465.         break;
  466.     case TCP_TIME_WAIT:     /* Sent and received SYN/FIN, all acked */
  467.         *sent -= 2;
  468.         *recvd -= 2;
  469.         break;
  470.     }
  471. }
  472.  
  473. /* TCP View Command - D. Crompton 1/92 */
  474. /* Modified for sorted display and     */
  475. /* two views - tcp view b|t - 3/92     */
  476.  
  477. static int
  478. doview(argc,argv,p)
  479. int argc;
  480. char *argv[];
  481. void *p;
  482.  
  483. {
  484.     register struct tcb *tcb;
  485.     int32 sent,recvd;
  486.     int i,j,k=0,vtype;
  487.     char *temp;
  488.     char *buf;
  489.  
  490.     if(argc == 1)
  491.     vtype = 1;
  492.     else {
  493.     switch (argv[1][0]) {
  494.         case 'b':  vtype=1;
  495.                break;
  496.         case 't':  vtype=0;
  497.                break;
  498.         default:   tprintf("Use: tcp view <bytes|timers>\n");
  499.                return 0;
  500.     }
  501.     }
  502.     
  503.     for(tcb=Tcbs,i=0;tcb != NULLTCB;tcb = tcb->next){
  504.         if(tcb->state == TCP_LISTEN)
  505.             continue;
  506.         i++;
  507.     }
  508.     
  509.     if (i) {
  510.      buf=mallocw((unsigned)i*80);
  511.      temp=mallocw(256);
  512.  
  513.      if (vtype) {
  514.       tprintf("                                               Send  Send       Receive Receive\n");
  515.       tprintf("Remote Socket:Port:Local Port/State   &TCB     Bytes Retries      Bytes Retries\n");
  516.      } else {
  517.       tprintf("Remote Socket:Port:Local Port/State   &TCB Boff State      Timer          SRTT\n");
  518.      }                                                                     
  519.      for(tcb=Tcbs,j=0;tcb != NULLTCB;tcb = tcb->next){
  520.         if(tcb->state == TCP_LISTEN)
  521.             continue;
  522.          
  523.         strcpy(temp,pinet(&tcb->conn.remote));
  524.         strcat(temp,strstr(pinet(&tcb->conn.local),":"));
  525.         strcat(temp,"/");
  526.         strcat(temp,Tcpstates[tcb->state]);
  527.         temp[37]=0;
  528.         k=sprintf(&buf[j],"%-37s",temp);
  529. #ifdef UNIX
  530.         k += sprintf(&buf[j + k], "%5lx", FP_SEG(tcb));
  531. #else
  532.         sprintf(temp,"%8lx",ptol(tcb));
  533.         temp[4]=0;
  534.         k+=sprintf(&buf[j+k]," %4s",temp);
  535. #endif
  536.         if (vtype) {
  537.           rxtx_data_compute(tcb,&sent,&recvd);
  538.           k+=sprintf(&buf[j+k],"%10lu ",sent);
  539.           k+=sprintf(&buf[j+k],"%7lu ",tcb->resent);
  540.           k+=sprintf(&buf[j+k],"%10lu ",recvd);
  541.           sprintf(&buf[j+k],"%7lu",tcb->rerecv);
  542.         } else {
  543.           k+=sprintf(&buf[j+k]," %4u",tcb->backoff);
  544.           if(tcb->flags.retran)
  545.               k+=sprintf(&buf[j+k]," Retry ");
  546.           else
  547.               k+=sprintf(&buf[j+k],"  Try  ");
  548.           switch(tcb->timer.state) {
  549.                case TIMER_STOP:
  550.                 k+=sprintf(&buf[j+k],"      Stopped");
  551.                 break;
  552.                case TIMER_RUN:
  553.                 k+=sprintf(&buf[j+k]," Run (");
  554.                 if ((long)dur_timer(&tcb->timer)<10000) {
  555.                   k+=sprintf(&buf[j+k],"%ld/%ld)ms",
  556.                    (long)read_timer(&tcb->timer),
  557.                    (long)dur_timer(&tcb->timer));
  558.                 } else {
  559.                 if (((long)read_timer(&tcb->timer)/1000)>9999) {
  560.                   k+=sprintf(&buf[j+k],">9999/9999)s");
  561.                 } else {
  562.                   k+=sprintf(&buf[j+k],"%ld/%ld)s",
  563.                    (long)read_timer(&tcb->timer)/1000,
  564.                    (long)dur_timer(&tcb->timer)/1000);
  565.                  }
  566.                 }
  567.                 break;
  568.                case TIMER_EXPIRE:
  569.                 k+=sprintf(&buf[j+k],"      Expired");
  570.           }
  571.           for (;k<73;k++)
  572.                buf[j+k]=' ';
  573.           if ((tcb->srtt)<10000) {
  574.               sprintf(&buf[j+73],"%4ldms",tcb->srtt);
  575.           } else {
  576.           if ((tcb->srtt/1000)>9999) {
  577.               sprintf(&buf[j+73],">9999s");
  578.           } else {
  579.               sprintf(&buf[j+73],"%4lds",tcb->srtt/1000);
  580.            }
  581.           }
  582.          }
  583.          j+=80;
  584.         }
  585.  
  586.         qsort(buf,(size_t)i,80,(int (*) __FARGS((const void*,const void*))) strcmp);
  587.  
  588.         for (j=0,k=0;j<i;j++,k+=80) {
  589.         tprintf("%s",&buf[k]);
  590.         if(tprintf("\n") == EOF)
  591.             return 0;
  592.         }
  593.      free(temp);
  594.         free(buf);
  595.       }
  596.     return 0;
  597. }
  598.  
  599. /* tcp timers type - linear v exponential */
  600. static int
  601. dotcptimer(argc,argv,p)
  602. int argc ;
  603. char *argv[] ;
  604. void *p ;
  605. {
  606.     extern int tcptimertype;
  607.  
  608.     if (argc < 2) {
  609.         tprintf("Tcp timer type is %s\n", tcptimertype ? "linear" : "exponential" ) ;
  610.         return 0 ;
  611.     }
  612.     
  613.     switch (argv[1][0]) {
  614.         case 'l':
  615.         case 'L':
  616.             tcptimertype = 1 ;
  617.             break ;
  618.         case 'e':
  619.         case 'E':
  620.             tcptimertype = 0 ;
  621.             break ;
  622.         default:
  623.             tprintf("use: tcp timertype [linear|exponential]\n") ;
  624.             return -1 ;
  625.     }
  626.  
  627.     return 0 ;
  628. }
  629. #ifdef  TCPACCESS
  630. static int
  631. doaccess(argc,argv,p)
  632. int argc;
  633. char *argv[];
  634. void *p;
  635. {
  636.     int32 target;
  637.     unsigned bits;
  638.     char *bitp;
  639.     int16 lport,hport,state;
  640.     char *cp; /* for printing the table */
  641.     struct rtaccess *tpacc;
  642.     struct rtaccess *head;
  643.     struct rtaccess *prev;
  644.  
  645.     if(argc == 1){ /* print out the table */
  646.         tprintf("IP Address      Mask  Low Port High Port State\n");
  647.         for(tpacc = TCPaccess;tpacc != NULLACCESS;tpacc = tpacc->nxtbits){
  648.             if(tpacc->target != 0)
  649.                 cp = inet_ntoa(tpacc->target);
  650.             else
  651.                 cp = "all";
  652.             tprintf("%-16s",cp);
  653.             tprintf("%4u ",tpacc->bits);
  654.             tprintf("%9u",tpacc->lowport);
  655.             tprintf("%10u ",tpacc->highport);
  656.             if(tpacc->status)
  657.                 cp = "deny";
  658.             else
  659.                 cp = "permit";
  660.             tprintf("%-6s\n",cp);
  661.         }
  662.         return 0;
  663.     }
  664.  
  665.     if(strcmp(argv[1],"permit") == 0){
  666.         state = 0;
  667.     } else {
  668.         if((strcmp(argv[1],"deny") == 0)
  669.         || (strcmp(argv[1],"delete") == 0)){
  670.             state = -1;
  671.         } else {
  672.             tprintf(" Format: tcp access <permit|deny|delete> <dest addr>[/<bits>] [lowport [highport]]\n");
  673.             return 1;
  674.         }
  675.     }
  676.     if(strcmp(argv[2],"all") == 0){
  677.         target = 0;
  678.         bits = 0;
  679.     } else {
  680.         /* If IP address is followed by an optional slash and
  681.          * a length field, (e.g., 128.96/16) get it;
  682.          * otherwise assume a full 32-bit address
  683.          */
  684.         if((bitp = strchr(argv[2],'/')) != NULLCHAR){
  685.             /* Terminate address token for resolve() call */
  686.             *bitp++ = '\0';
  687.             bits = atoi(bitp);
  688.         } else
  689.             bits = 32;
  690.  
  691.         if((target = resolve(argv[2])) == 0){
  692.             tprintf(Badhost,argv[2]);
  693.             return 1;
  694.         }
  695.     }
  696.  
  697.     if(argc > 3){
  698.         if(strcmp(argv[3],"all") == 0){
  699.             lport = 1;
  700.             hport = 65534;
  701.         } else {
  702.             lport = atoi(argv[3]);
  703.             hport = lport;
  704.         }
  705.     } else {
  706.         lport = 0;
  707.         hport = 0;
  708.     }
  709.     if(argc > 4)
  710.         hport = atoi(argv[4]);
  711.  
  712.     if(strcmp(argv[1],"delete") == 0){
  713.         prev = NULLACCESS;
  714.         head = tpacc = TCPaccess;
  715.         while(tpacc != NULLACCESS){
  716.             head = tpacc;
  717.             tpacc = tpacc->nxtbits;
  718.             if((head->target == target) &&
  719.                (head->bits == bits)     &&
  720.                (head->lowport == lport) &&
  721.                (head->highport == hport)) { /*match*/
  722.  
  723.  
  724.                 /*now delete. watch for special cases*/
  725.                 if(head == TCPaccess) /* first in chain */
  726.                     TCPaccess = head->nxtbits;
  727.                 else
  728.                     /*
  729.                       sanity check: we cant get here with
  730.                       prev == NULLACCESS !!
  731.                      */
  732.                     prev->nxtbits = tpacc;
  733.                 free(head);
  734.                 return 0;
  735.             }
  736.             prev = head;
  737.         }
  738.         tprintf("Not found.\n");
  739.         return 1;
  740.     }
  741.     /* add the access */
  742.     addtaccess(target,bits,lport,hport,state);
  743.     return 0;
  744. }
  745. /* add an entry to the access control list */
  746. /* not a lot of error checking 8-) */
  747. void
  748. addtaccess(target,bits,low,high,permit)
  749. int32 target;           /* Target IP address prefix */
  750. unsigned int bits;      /* Size of target address prefix in bits (0-32) */
  751. int16 low;
  752. int16 high;
  753. int16 permit;
  754. {
  755.     struct rtaccess *tpacc; /*temporary*/
  756.     struct rtaccess *holder; /*for the new record*/
  757.  
  758.     holder = (struct rtaccess *)callocw(1,sizeof(struct rtaccess));
  759.     holder->nxtiface = NULLACCESS;
  760.     holder->nxtbits = NULLACCESS;
  761.     holder->target = target;
  762.     holder->bits = bits;
  763.     holder->lowport = low;
  764.     holder->highport = high;
  765.     holder->status = permit;
  766.     if((tpacc = TCPaccess) == NULLACCESS){
  767.         TCPaccess = holder;
  768.     } else {
  769.         while(tpacc->nxtbits != NULLACCESS)
  770.             tpacc = tpacc->nxtbits;
  771.         tpacc->nxtbits = holder;
  772.     }
  773. }
  774. /* check to see if port is "authorized".  Returns 0 if matching permit record
  775.    is found or no access records exists, -1 if not found or deny record found */
  776. int
  777. tcp_check(accptr,src,port)
  778. struct rtaccess *accptr;
  779. int32 src;
  780. int16 port;
  781. {
  782.     unsigned long mask;
  783.  
  784.     if(accptr == NULLACCESS)
  785.         return 0;               /* no access control */
  786.     for(;accptr != NULLACCESS;accptr = accptr->nxtbits) {
  787.         mask = ~0L << (32 - accptr->bits);
  788.         if(( accptr->target == (mask & src)) &&
  789.           ((( port >= accptr->lowport ) && (port <= accptr->highport))
  790.            || (!accptr->lowport))){
  791.             return (accptr->status);
  792.         }
  793.     }
  794.     return -1; /* fall through to here if not found */
  795. }
  796. #endif
  797.  
  798.